#include <queue>
#include<pthread.h>


template <typename T>
class BlockQueue
{
public:
    BlockQueue(int cap) : _cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_productor_cond, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
    }
    bool IsFull()
    {
        return _block_queue.size() == _cap;
    }
    bool IsEmpty()
    {
        return _block_queue.empty();
    }
    void Enqueue(T in)
    {
        pthread_mutex_lock(&_mutex);//加锁
        while (IsFull()) //防止伪唤醒，每一个被唤醒的线程需要重新进行一次判断
        {
            pthread_cond_wait(&_productor_cond, &_mutex);
        }
        _block_queue.push(in);//生产
        pthread_mutex_unlock(&_mutex);//解锁
        pthread_cond_signal(&_consumer_cond);//走到这里说明生产者了生产了，可以唤醒一位消费者了
    }

    void pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while (IsEmpty())
        {
            pthread_cond_wait(&_consumer_cond, &_mutex);
        }
        //消费
        *out = _block_queue.front();
        _block_queue.pop();

        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_productor_cond);//唤醒生产者
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_productor_cond);
        pthread_cond_destroy(&_consumer_cond);
    }

private:
    int _cap;
    std::queue<T> _block_queue;     // 阻塞队列
    pthread_mutex_t _mutex;         // 资源的锁
    pthread_cond_t _productor_cond; // 生产者的条件变量
    pthread_cond_t _consumer_cond;  // 消费者的条件变量
};